home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-01 / grep.zip / GREP.C < prev    next >
Text File  |  1993-01-04  |  14KB  |  565 lines

  1. #include <stdio.h>
  2. #include <ctype.h>
  3. #include <dos.h>
  4. #include <dir.h>
  5. #include <process.h>
  6. #include <string.h>
  7. #include <mem.h>
  8. #include <errno.h>
  9. #include "grep.h"
  10.  
  11. main(argc, argv)
  12. char *argv[];
  13. {
  14.             char   *p;
  15.    register int    i;
  16.    register char   c;
  17.    int             gotpattern;
  18.    int             count, start;
  19.  
  20.  
  21.    FILE            *f;
  22.    char            *fname;
  23.  
  24.    if (argc <= 1)
  25.       usage("No arguments");
  26.    if (argc == 2 && argv[1][0] == '?' && argv[1][1] == 0) {
  27.       help(documentation);
  28.       help(patdoc);
  29.       return;
  30.       }
  31.    nfile = argc-1;
  32.    gotpattern = 0;
  33.    for (i=1; i < argc; ++i) {
  34.       p = argv[i];
  35.       if (*p == '-') {
  36.          ++p;
  37.          while ( (c = *p++) != 0)
  38.          {
  39.             switch(tolower(c)) {
  40.  
  41.             case '?':
  42.                help(documentation);
  43.                break;
  44.  
  45.             case 'C':
  46.             case 'c':
  47.                ++cflag;
  48.                break;
  49.  
  50.             case 'D':
  51.             case 'd':
  52.                ++debug;
  53.                break;
  54.  
  55.             case 'F':
  56.             case 'f':
  57.                ++fflag;
  58.                break;
  59.  
  60.             case 'n':
  61.             case 'N':
  62.                ++nflag;
  63.                break;
  64.  
  65.             case 'v':
  66.             case 'V':
  67.                ++vflag;
  68.                break;
  69.  
  70.             default:
  71.                usage("Unknown flag");
  72.             }
  73.          }
  74.          argv[i] = 0;
  75.          --nfile;
  76.       } else if (!gotpattern) {
  77.          compile(p);
  78.          argv[i] = 0;
  79.          ++gotpattern;
  80.          --nfile;
  81.       }
  82.    }
  83.    if (!gotpattern)
  84.       usage("No pattern");
  85.    if (nfile == 0)
  86.       grep(stdin, 0);
  87.    else
  88.    {
  89.       fflag = fflag ^ (nfile > 0);
  90.       for (i=1; i < argc; ++i)
  91.       {
  92.          if ( (p = argv[i]) != 0)
  93.          {
  94.             count = getfnl(p,fnames,FNASIZE,6);
  95.             if (count > 0)
  96.             {
  97.                if (strbpl(fpointers, MAXFILES, fnames) != count)
  98.                   toomany(p);
  99.                else
  100.                {
  101.                   start = 0;
  102.                   while ( (fname = fpointers[start++]) != 0)
  103.                   {
  104.                      if ((f=fopen(fname, "r")) == NULL)
  105.                         cant(fname);
  106.                      else
  107.                      {
  108.                         grep(f, fname);
  109.                         fclose(f);
  110.                      }
  111.                   }
  112.                }
  113.             }
  114.             else
  115.             {
  116.                if (errno == ENOMEM)
  117.                   toomany(p);
  118.                else
  119.                   cant(p);
  120.             }
  121.          }
  122.       }
  123.    }
  124. }
  125.  
  126. /*******************************************************/
  127.  
  128. void file(s)
  129. char *s;
  130. {
  131.    if (lfeed++)
  132.       printf("\n");
  133.    printf("File %s:\n", s);
  134. }
  135.  
  136. /*******************************************************/
  137.  
  138. void toomany(s)
  139. char *s;
  140. {
  141.    strupr(s);
  142.    fprintf(stderr,"\nGREP: too many file names - %s\n", s);
  143. }
  144.  
  145. void cant(s)
  146. char *s;
  147. {
  148.    strupr(s);
  149.    fprintf(stderr, "\nGREP: bad path name or file not found - %s\n", s);
  150. }
  151.  
  152.  
  153. /*******************************************************/
  154.  
  155. void help(hp)
  156. char **hp;  /* dns added extra '*'  */
  157. /*
  158.  * Give good help
  159.  */
  160. {
  161.    register char   **dp;
  162.  
  163.    for (dp = hp; *dp; dp++)
  164.       printf("%s\n", *dp);
  165. }
  166.  
  167.  
  168. /*******************************************************/
  169.  
  170. void usage(s)
  171. char    *s;
  172. {
  173.    fprintf(stderr, "GREP: %s\n", s);
  174.    fprintf(stderr,
  175.       "Usage: grep [-cfnv] pattern [file ...].  grep ? for help\n");
  176.    exit(1);
  177. }
  178.  
  179.  
  180.  
  181. /*******************************************************/
  182.  
  183.  
  184. void compile(source)
  185. char       *source;   /* Pattern to compile         */
  186. /*
  187.  * Compile the pattern into global pbuf[]
  188.  */
  189. {
  190.             char  *s;         /* Source string pointer     */
  191.             char  *lp;        /* Last pattern pointer      */
  192.    register char  c;          /* Current character         */
  193.    int            o;          /* Temp                      */
  194.    char           *spp;       /* Save beginning of pattern */
  195.    char           *cclass();  /* Compile class routine     */
  196.  
  197.    s = source;
  198.    lp = NULL;
  199.    if (debug)
  200.       printf("Pattern = \"%s\"\n", s);
  201.    pp = pbuf;
  202.    while ( (c = *s++) != 0)
  203.    {
  204.       /*
  205.        * STAR, PLUS and MINUS are special.
  206.        */
  207.       if (c == '*' || c == '+' || c == '-') {
  208.          if (pp == pbuf ||
  209.               (o=pp[-1]) == BOL ||
  210.               o == EOL ||
  211.               o == STAR ||
  212.               o == PLUS ||
  213.               o == MINUS)
  214.             badpat("Illegal occurrance op.", source, s);
  215.          store(ENDPAT);
  216.          store(ENDPAT);
  217.          spp = pp;               /* Save pattern end     */
  218.          while (--pp > lp)       /* Move pattern down    */
  219.             *pp = pp[-1];        /* one byte             */
  220.          *pp =   (c == '*') ? STAR :
  221.             (c == '-') ? MINUS : PLUS;
  222.          pp = spp;               /* Restore pattern end  */
  223.          continue;
  224.       }
  225.       /*
  226.        * All the rest.
  227.        */
  228.       lp = pp;         /* Remember start       */
  229.       switch(c) {
  230.  
  231.       case '^':
  232.          store(BOL);
  233.          break;
  234.  
  235.       case '$':
  236.          store(EOL);
  237.          break;
  238.  
  239.       case '.':
  240.          store(ANY);
  241.          break;
  242.  
  243.       case '[':
  244.          s = cclass(source, s);
  245.          break;
  246.  
  247.       case ':':
  248.          if (*s) {
  249.             c = *s++;
  250.             switch(tolower(c)) {
  251.  
  252.             case 'a':
  253.             case 'A':
  254.                store(ALPHA);
  255.                break;
  256.  
  257.             case 'd':
  258.             case 'D':
  259.                store(DIGIT);
  260.                break;
  261.  
  262.             case 'n':
  263.             case 'N':
  264.                store(NALPHA);
  265.                break;
  266.  
  267.             case ' ':
  268.                store(PUNCT);
  269.                break;
  270.  
  271.             default:
  272.                badpat("Unknown : type", source, s);
  273.  
  274.             }
  275.             break;
  276.          }
  277.          else    badpat("No : type", source, s);
  278.  
  279.       case '\\':
  280.          if (*s)
  281.             c = *s++;
  282.  
  283.       default:
  284.          store(CHAR);
  285.          store(tolower(c));
  286.       }
  287.    }
  288.    store(ENDPAT);
  289.    store(0);                /* Terminate string     */
  290.    if (debug) {
  291.       for (lp = pbuf; lp < pp;) {
  292.          if ((c = (*lp++ & 0377)) < ' ')
  293.             printf("\\%o ", c);
  294.          else    printf("%c ", c);
  295.         }
  296.         printf("\n");
  297.    }
  298. }
  299.  
  300. /*******************************************************/
  301.  
  302. char *
  303. cclass(source, src)
  304. char       *source;   /* Pattern start -- for error msg.      */
  305. char       *src;      /* Class start           */
  306. /*
  307.  * Compile a class (within [])
  308.  */
  309. {
  310.    register char   *s;        /* Source pointer    */
  311.    register char   *cp;       /* Pattern start     */
  312.    register int    c;         /* Current character */
  313.    int             o;         /* Temp              */
  314.  
  315.    s = src;
  316.    o = CLASS;
  317.    if (*s == '^') {
  318.       ++s;
  319.       o = NCLASS;
  320.    }
  321.    store(o);
  322.    cp = pp;
  323.    store(0);                          /* Byte count      */
  324.    while ( ((c = *s++) != 0) && c != ']')
  325.    {
  326.       if (c == '\\') {                /* Store quoted char    */
  327.          if ((c = *s++) == '\0')      /* Gotta get something  */
  328.             badpat("Class terminates badly", source, s);
  329.          else    store(tolower(c));
  330.       }
  331.       else if (c == '-' &&
  332.             (pp - cp) > 1 && *s != ']' && *s != '\0') {
  333.          c = pp[-1];             /* Range start     */
  334.          pp[-1] = RANGE;         /* Range signal    */
  335.          store(c);               /* Re-store start  */
  336.          c = *s++;               /* Get end char and*/
  337.          store(tolower(c));      /* Store it        */
  338.       }
  339.       else {
  340.          store(tolower(c));      /* Store normal char */
  341.       }
  342.    }
  343.    if (c != ']')
  344.       badpat("Unterminated class", source, s);
  345.    if ((c = (pp - cp)) >= 256)
  346.       badpat("Class too large", source, s);
  347.    if (c == 0)
  348.       badpat("Empty class", source, s);
  349.    *cp = c;
  350.    return(s);
  351. }
  352.  
  353. /*******************************************************/
  354.  
  355. void store(op)
  356. char op;
  357. {
  358.    if (pp >= &pbuf[PMAX])
  359.       error("Pattern too complex\n");
  360.    *pp++ = op;
  361. }
  362.  
  363.  
  364. /*******************************************************/
  365.  
  366. void badpat(message, source, stop)
  367. char  *message;       /* Error message */
  368. char  *source;        /* Pattern start */
  369. char  *stop;          /* Pattern end   */
  370. {
  371.    fprintf(stderr, "GREP: %s, pattern is\"%s\"\n", message, source);
  372.    fprintf(stderr, "GREP: Stopped at byte %d, character '%c'\n",
  373.          stop-source, stop[-1]);
  374.    error("GREP: Bad pattern\n");
  375. }
  376.  
  377.  
  378.  
  379. /*******************************************************/
  380.  
  381. void grep(fp, fn)
  382. FILE       *fp;       /* File to process            */
  383. char       *fn;       /* File name (for -f option)  */
  384. /*
  385.  * Scan the file for the pattern in pbuf[]
  386.  */
  387. {
  388.    register int lno, count, m;
  389.  
  390.    lno = 0;
  391.    count = 0;
  392.    while (fgets(lbuf, LMAX, fp)) {
  393.       ++lno;
  394.       m = match();
  395.       if ((m && !vflag) || (!m && vflag)) {
  396.          ++count;
  397.          if (!cflag) {
  398.             if (fflag && fn) {
  399.                file(fn);
  400.                fn = 0;
  401.             }
  402.             if (nflag)
  403.                printf("%d\t", lno);
  404.             printf("%s", lbuf);
  405.             /*printf("%s\n", lbuf);*/
  406.          }
  407.       }
  408.    }
  409.    if (cflag) {
  410.       if (fflag && fn)
  411.          file(fn);
  412.       printf("%d\n", count);
  413.    }
  414. }
  415.  
  416.  
  417. /*******************************************************/
  418.  
  419. int match()
  420. /*
  421.  * Match the current line (in lbuf[]), return 1 if it does.
  422.  */
  423. {
  424.    register char   *l;        /* Line pointer       */
  425.    char *pmatch();
  426.  
  427.    for (l = lbuf; *l; l++) {
  428.       if (pmatch(l, pbuf))
  429.          return(1);
  430.    }
  431.    return(0);
  432. }
  433.  
  434. /*******************************************************/
  435.  
  436. char *
  437. pmatch(line, pattern)
  438. char               *line;     /* (partial) line to match      */
  439. char               *pattern;  /* (partial) pattern to match   */
  440. {
  441.    register char   *l;        /* Current line pointer         */
  442.    register char   *p;        /* Current pattern pointer      */
  443.    register char   c;         /* Current character            */
  444.    char            *e;        /* End for STAR and PLUS match  */
  445.    int             op;        /* Pattern operation            */
  446.    int             n;         /* Class counter                */
  447.    char            *are;      /* Start of STAR match          */
  448.  
  449.    l = line;
  450.    if (debug > 1)
  451.       printf("pmatch(\"%s\")\n", line);
  452.    p = pattern;
  453.    while ((op = *p++) != ENDPAT) {
  454.       if (debug > 1)
  455.          printf("byte[%d] = 0%o, '%c', op = 0%o\n",
  456.                l-line, *l, *l, op);
  457.       switch(op) {
  458.  
  459.       case CHAR:
  460.          if (tolower(*l++) != *p++)
  461.             return(0);
  462.          break;
  463.  
  464.       case BOL:
  465.          if (l != lbuf)
  466.             return(0);
  467.          break;
  468.  
  469.       case EOL:
  470.          if (*l != '\0')
  471.             return(0);
  472.          break;
  473.  
  474.       case ANY:
  475.          if (*l++ == '\0')
  476.             return(0);
  477.          break;
  478.  
  479.       case DIGIT:
  480.          if ((c = *l++) < '0' || (c > '9'))
  481.             return(0);
  482.          break;
  483.  
  484.       case ALPHA:
  485.          c = tolower(*l++);
  486.          if (c < 'a' || c > 'z')
  487.             return(0);
  488.          break;
  489.  
  490.       case NALPHA:
  491.          c = tolower(*l++);
  492.          if (c >= 'a' && c <= 'z')
  493.             break;
  494.          else if (c < '0' || c > '9')
  495.             return(0);
  496.          break;
  497.  
  498.       case PUNCT:
  499.          c = *l++;
  500.          if (c == 0 || c > ' ')
  501.             return(0);
  502.          break;
  503.  
  504.       case CLASS:
  505.       case NCLASS:
  506.          c = tolower(*l++);
  507.          n = *p++ & 0377;
  508.          do {
  509.             if (*p == RANGE) {
  510.                p += 3;
  511.                n -= 2;
  512.                if (c >= p[-2] && c <= p[-1])
  513.                   break;
  514.             }
  515.             else if (c == *p++)
  516.                break;
  517.          } while (--n > 1);
  518.          if ((op == CLASS) == (n <= 1))
  519.             return(0);
  520.          if (op == CLASS)
  521.             p += n - 2;
  522.          break;
  523.  
  524.       case MINUS:
  525.          e = pmatch(l, p);       /* Look for a match    */
  526.          while (*p++ != ENDPAT); /* Skip over pattern   */
  527.          if (e)                  /* Got a match?        */
  528.             l = e;               /* Yes, update string  */
  529.          break;                  /* Always succeeds     */
  530.  
  531.       case PLUS:                 /* One or more ...     */
  532.          if ((l = pmatch(l, p)) == 0)
  533.             return(0);           /* Gotta have a match  */
  534.       case STAR:                 /* Zero or more ...    */
  535.          are = l;                /* Remember line start */
  536.          while ( (*l != 0) && ((e = pmatch(l, p)) != 0) )
  537.             l = e;               /* Get longest match   */
  538.          while (*p++ != ENDPAT); /* Skip over pattern   */
  539.          while (l >= are) {      /* Try to match rest   */
  540.             if ( (e = pmatch(l, p)) != 0)
  541.                return(e);
  542.             --l;                 /* Nope, try earlier   */
  543.          }
  544.          return(0);              /* Nothing else worked */
  545.  
  546.       default:
  547.          printf("Bad op code %d\n", op);
  548.          error("Cannot happen -- match\n");
  549.       }
  550.    }
  551.    return(l);
  552. }
  553.  
  554. /*******************************************************/
  555.  
  556. void error(s)
  557. char *s;
  558. {
  559.    fprintf(stderr, "%s", s);
  560.    exit(1);
  561. }
  562.  
  563. /*******************************************************/
  564.  
  565.